package com.rois.librois.libRoISComp;

import java.util.Vector;
import java.util.logging.Logger;

import com.rois.librois.RoIS.Completed_Status;
import com.rois.librois.RoIS.ErrorType;
import com.rois.librois.RoIS.Result;
import com.rois.librois.RoIS.ResultListHolder;
import com.rois.librois.libRoISComp.ComponentEntity;
import com.rois.librois.libRoISComp.MessageParameter;

/**
 * API for command line control.
 *
 * @author Miki Sato <miki.sato.1225@gmail.com>
 *
 *    The MIT licence
 *
 *    Copyright (C) 2011
 *      ATR Intelligent Robotics and Communication Laboratories, Japan
 *
 *    Permission is hereby granted, free of charge, to any person obtaining a copy
 *    of this software and associated documentation files (the "Software"), to deal
 *    in the Software without restriction, including without limitation the rights
 *    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 *    of the Software, and to permit persons to whom the Software is furnished to do so,
 *    subject to the following conditions:
 *
 *    The above copyright notice and this permission notice shall be included in all
 *    copies or substantial portions of the Software.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 *    INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 *    PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *    OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 *    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

public class CommandControl {
	private static libRoISComp lib;
	private static ComponentEntity comp;
	private boolean state = false;

	/**
	 * create command control
	 * @param lib_obj libRoIS object
	 * @param comp_obj ComponentEntity object
	 */
	public CommandControl(
		libRoISComp lib_obj,
		ComponentEntity comp_obj
	)
	{
		lib = lib_obj;
		comp = comp_obj;
	}

	///////////////////////////////////////////////////
	// for RoIS Interface
	///////////////////////////////////////////////////
	/**
	 * call "connect" method of libRoISComp
	 * @return true/false
	 */
	public boolean connect()
	{
		// send message
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("send [connect] message");
		return lib.connect();
	}

	/**
	 * call "disconnect" method of libRoISComp
	 * @return true/false
	 */
	public boolean disconnect()
	{
		// send message
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("send [disconnect] message");
		return lib.disconnect();
	}

	/**
	 * call "completed" method of libRoISComp
	 * @param command_id ID of the received command message
	 * @param status status of the command completion
	 * @return true/false
	 */
	public boolean sendCompleted(
		String command_id,
		String status
	)
	{
		boolean bRes = false;

		// check command id
		if(command_id.isEmpty())
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("command ID is not give");
			return bRes;
		}

		// check status
		Completed_Status rois_status = null;
		if(status.matches("ok"))
		{
			rois_status = Completed_Status.CMD_OK;
		}
		else if(status.matches("error"))
		{
			rois_status = Completed_Status.CMD_ERROR;
		}
		else if(status.matches("abort"))
		{
			rois_status = Completed_Status.CMD_ERROR;
		}
		else if(status.matches("timeout"))
		{
			rois_status = Completed_Status.CMD_TIMEOUT;
		}
		else if(status.matches("resource"))
		{
			rois_status = Completed_Status.CMD_OUT_OF_RESOURCES;
		}
		else
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("component status is not correct");
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("[ok] [error] [abort] [timeout] [resource]");
			return bRes;
		}

		// create result parameter
		ResultListHolder _results = new ResultListHolder();
		//@@ FOR DUMMY: dummy result palameter for command_completed
		_results.value = new Result[1];
		_results.value[0] = new Result();
		_results.value[0].name = "test_cmd_result";
		_results.value[0].data_type_ref = "string";
		String str_tmp = "test_value_for_cmd";
		org.omg.CORBA.Any any_tmp = org.omg.CORBA.ORB.init().create_any();
		any_tmp.insert_string(str_tmp);
		_results.value[0].value = any_tmp;

		// send message
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("send [completed] message");
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("-command ID: " + command_id);
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("-command status: " + status);
		lib.completed(command_id, rois_status, _results);
		bRes = true;
		return bRes;
	}

	/**
	 * call "receive_event" method of libRoISComp
	 * @param event_type type of the subscribed event
	 * @param subscribe_id ID of the subscribed event
	 * @return true/false
	 */
	public boolean sendEvent(
		String event_type,
		String subscribe_id
	)
	{
		boolean bRes = false;

		// check event type
		if(event_type.isEmpty())
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("event type is not given");
			return bRes;
		}

		// check command id
		if(subscribe_id.isEmpty())
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("subscribe ID is not given");
			return bRes;
		}

		// create result parameter
		ResultListHolder _results = new ResultListHolder();
		MessageParameter[] event_params = new MessageParameter[comp.get_event_prameter_size()];
		comp.get_event_parameters(event_params);
		for(int i=0; i<comp.get_event_prameter_size(); i++)
		{
			if(event_params[i].message_type.matches(event_type))
			{
				int size = event_params[i].parameters.length;
				_results.value = new Result[size];
				for(int j=0; j<size; j++)
				{
					_results.value[j] = new Result();
					_results.value[j].name = event_params[i].parameters[j].name;
					_results.value[j].data_type_ref = event_params[i].parameters[j].data_type_ref;
					//@@ FOR DUMMY: no result parameter for event
					event_params[i].parameters[j].setParam("");
			 		org.omg.CORBA.Any any_tmp = org.omg.CORBA.ORB.init().create_any();
			 		any_tmp.insert_string(event_params[i].parameters[j].getParam());
			 		_results.value[j].value = any_tmp;
				}
			}
		}

		// send message
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("send [receive_event] message");
		lib.receive_event(event_type, subscribe_id, _results);
		return bRes;
	}

	/**
	 * call "receive_error" method of libRoISComp
	 * @param error_type type of the error
	 * @return true/false
	 */
	public boolean sendError(
			String error_type
		)
		{
			boolean bRes = false;

			// check error type
			ErrorType rois_type = null;
			if(error_type.matches("comp"))
			{
				rois_type = ErrorType.COMPONENT_INTERNAL_ERROR;
			}
			else if(error_type.matches("response"))
			{
				rois_type = ErrorType.COMPONENT_NOT_RESPONDING;
			}
			else if(error_type.matches("engine"))
			{
				rois_type = ErrorType.ENGINE_INTERNAL_ERROR;
			}
			else if(error_type.matches("user"))
			{
				rois_type = ErrorType.USER_DEFINED_ERROR;
			}
			else
			{
				Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("error type is not correct");
				Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("[comp] [response] [engine] [user]");
				return bRes;
			}

			// create result parameter
			ResultListHolder _results = new ResultListHolder();
			//@@ FOR DUMMY: dummy result palameter for error
			_results.value = new Result[1];
			_results.value[0] = new Result();
			_results.value[0].name = "test_error";
			_results.value[0].data_type_ref = "string";
			String str_tmp = "test_value_for_error";
			org.omg.CORBA.Any any_tmp = org.omg.CORBA.ORB.init().create_any();
			any_tmp.insert_string(str_tmp);
			_results.value[0].value = any_tmp;

			// send message
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("send [receive_error] message");
			lib.receive_error(rois_type, _results);
			bRes = true;
			return bRes;
		}

	///////////////////////////////////////////////////
	// for Debug
	///////////////////////////////////////////////////

	/**
	 * start.
	 * @param comp_obj component entity object
	 * @return true/false
	 */
	public boolean start(ComponentEntity comp_obj)
	{
		state = lib.initialize(comp_obj);
		return state;
	}

	/**
	 * stop.
	 * @param N/A
	 */
	public void stop()
	{
		if(state)
		{
			// send message
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("send [disconnect] message");
			lib.disconnect();
			lib.finalize();
			state = false;
		}
	}

	/**
	 * show a list of connecting engines.
	 * @return true/false
	 */
	public boolean showConnectEngineList()
	{
		boolean bRes = false;
		Vector<String> servername_list = new Vector<String>();
		Vector<String> nameservice_list = new Vector<String>();
		int size = lib.getConnectingEngineList(servername_list, nameservice_list);
		for(int i=0; i<size; i++)
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(
				"(" + String.valueOf(i) + ")"
				+ servername_list.get(i)
				+ "/" + nameservice_list.get(i)
			);
			bRes = true;
		}
		return bRes;
	}

	/**
	 * show a list of binding engines.
	 * @return true/false
	 */
	public boolean showBindEngineList()
	{
		boolean bRes = false;
		Vector<String> servername_list = new Vector<String>();
		Vector<Vector<String>> command_types_list = new Vector<Vector<String>>();
		Vector<Vector<String>> command_ids_list = new Vector<Vector<String>>();
		int requested_engine_size = lib.getBindingEngineList(
			servername_list,
			command_types_list,
			command_ids_list
		);
		for(int i=0; i<requested_engine_size; i++)
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(
				"(" + String.valueOf(i) + ")"
				+ servername_list.get(i)
				+ " x "+ String.valueOf(command_types_list.get(i).size())
			);
			bRes = true;
		}
		return bRes;
	}

	/**
	 * show a list of requested command messages.
	 * @return true/false
	 */
	public boolean showRequestedCommandList()
	{
		boolean bRes = false;
		Vector<String> servername_list = new Vector<String>();
		Vector<Vector<String>> command_types_list = new Vector<Vector<String>>();
		Vector<Vector<String>> command_ids_list = new Vector<Vector<String>>();
		int requested_engine_size = lib.getBindingEngineList(
			servername_list,
			command_types_list,
			command_ids_list
		);
		for(int i=0; i<requested_engine_size; i++)
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(
				"(" + String.valueOf(i) + ")requested by "
				+ servername_list.get(i)
			);
			int request_count = command_ids_list.get(i).size();
			for(int j=0; j<request_count; j++)
			{
				Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(
					"-[" + String.valueOf(j) + "]"
					+ "type:" + command_types_list.get(i).get(j)
					+ "/command ID:" + command_ids_list.get(i).get(j)
				);
			}
			bRes = true;
		}
		return bRes;
	}

	/**
	 * show a list of completed command messages.
	 * @return true/false
	 */
	public boolean showCompletedCommandList()
	{
		boolean bRes = false;
		Vector<String> servername_list = new Vector<String>();
		Vector<Vector<String>> command_types_list = new Vector<Vector<String>>();
		Vector<Vector<String>> command_ids_list = new Vector<Vector<String>>();
		int requested_engine_size = lib.getBindingEngineList(
			servername_list,
			command_types_list,
			command_ids_list
		);
		for(int i=0; i<requested_engine_size; i++)
		{
			Vector<String> type_list = new Vector<String>();
			Vector<String> id_list = new Vector<String>();
			Vector<String> status_list = new Vector<String>();
			int engine_index = lib.getEngineIndexByServername(servername_list.get(i));
			int cmd_size = lib.getSentCompletedMessages(
				engine_index,
				type_list,
				id_list,
				status_list
			);
			for(int j=0; j<cmd_size; j++)
			{
				Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(
					"(" + String.valueOf(i) + ")"
					+ servername_list.get(i) + ":"
					+ type_list.get(j) + "/"
					+ id_list.get(j) + "/"
					+ status_list.get(j)
				);
				bRes = true;
			}
		}
		return bRes;
	}

	/**
	 * show a list of subscribe event messages
	 * @return true/false
	 */
	public boolean showSubscribeEventList()
	{
		boolean bRes = false;
		Vector<String> servername_list = new Vector<String>();
		Vector<Vector<String>> subscribe_types_list = new Vector<Vector<String>>();
		Vector<Vector<String>> subscribe_ids_list = new Vector<Vector<String>>();
		int subscribed_engine_size = lib.getSubscribingEngineList(
			servername_list,
			subscribe_types_list,
			subscribe_ids_list
		);
		for(int i=0; i<subscribed_engine_size; i++)
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(
				"(" + String.valueOf(i) + ")subscribed by "
				+ servername_list.get(i)
			);
			int subscribe_count = subscribe_ids_list.get(i).size();
			for(int j=0; j<subscribe_count; j++)
			{
				Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(
					"-[" + String.valueOf(j) + "]"
					+ "type:" + subscribe_types_list.get(i).get(j)
					+ "/subscribe ID:" + subscribe_ids_list.get(i).get(j)
				);
			}
			bRes = true;
		}
		return bRes;
	}

	/**
	 * show a list of sent event messages.
	 * @return true/false
	 */
	public boolean showSentEventList()
	{
		boolean bRes = false;
		Vector<String> servername_list = new Vector<String>();
		Vector<Vector<String>> subscribe_types_list = new Vector<Vector<String>>();
		Vector<Vector<String>> subscribe_ids_list = new Vector<Vector<String>>();
		int subscribed_engine_size = lib.getSubscribingEngineList(
			servername_list,
			subscribe_types_list,
			subscribe_ids_list
		);
		for(int i=0; i<subscribed_engine_size; i++)
		{
			for(int j=0; j<subscribe_ids_list.get(i).size(); j++)
			{
				Vector<String> type_list = new Vector<String>();
				Vector<String> subscribe_id_list = new Vector<String>();
				Vector<String> event_id_list = new Vector<String>();
				int engine_index = lib.getEngineIndexByServername(servername_list.get(i));
				int evt_size = lib.getSentEventMessages(
					engine_index,
					j,
					type_list,
					subscribe_id_list,
					event_id_list
				);
				for(int k=0; k<evt_size; k++)
				{
					Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(
						"(" + String.valueOf(i) + ")"
						+ servername_list.get(i) + ":"
						+ type_list.get(k) + "/"
						+ subscribe_id_list.get(k) + "/"
						+ event_id_list.get(k)
					);
					bRes = true;
				}
			}
		}
		return bRes;
	}

	/**
	 * show a list of sent error messages.
	 * @return true/false
	 */
	public boolean showSentErrorList()
	{
		boolean bRes = false;
		Vector<String> error_types_list = new Vector<String>();
		Vector<String> error_ids_list = new Vector<String>();
		int error_size = lib.getSentErrorMessages(
			error_types_list,
			error_ids_list
		);
		for(int i=0; i<error_size; i++)
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(
				"(" + String.valueOf(i) + ")"
				+ error_types_list.get(i) + ":"
				+ error_ids_list.get(i)
			);
			bRes = true;
		}
		return bRes;
	}
}
